<script lang="ts" setup>
import type { RowSelectionType, SpColumnsType } from '@/components/SpTable/type'
import Icon from '@/components/icon/Icon.vue'
import Draggable from 'vuedraggable'
import { transformI18n } from '@/plugins/i18n'

type SpTableProps = {
  /** 列配置 */
  columnList: SpColumnsType[]
  /** 数据 */
  data: any[]
  /** 加载状态 */
  loading?: boolean
  /** 分页配置 */
  paging?: PagingParams
  /** 表格大小 */
  tableSize?: 'middle' | 'small' | 'large'
  /** 列key */
  rowKey?: (record: any) => any
  /** 是否展示外边框和列边框 */
  bordered?: boolean
  /** 表格行的类名 */
  rowClassName?: (record: any, index: number) => string | null
  /** 设置是否允许行展开 */
  rowExpandable?: (record: any) => boolean
  /* 	列表项是否可选择，配置项 */
  rowSelection?: RowSelectionType
  /* 列表是否显示导出按钮 */
  deriveButton?: boolean
  /* 导出按钮权限 */
  deriveButtonPerms?: string
  /** 批量删除按钮 */
  deleteButton?: boolean
  /* 批量删除权限 */
  deleteButtonPerms?: string
  /* 初始时，是否展开所有行 */
  defaultExpandAllRows?: boolean
  /** 新增按钮 */
  addButton?: boolean
  /* 新增按钮权限 */
  addButtonPerms?: string
  /** 打印按钮 */
  printButton?: boolean
  /* 打印按钮权限 */
  printButtonPerms?: string
  /**  表格是否可滚动（设置了这个，一定全部列给宽度宽度）  */
  scroll?: { x?: string | number | true; y?: string | number }
}

// 事件
const emit = defineEmits<{
  /**
   * 分页变化
   * @param e
   * @param page 当前页
   * @param pageSize 当前页数量
   */
  (e: 'paginationChange', page: number, pageSize: number): void
  /**
   * 批量删除
   * @param e
   * @param ids 选中项
   */
  (e: 'batchDeleteChange', ids: number[]): void
  /**
   * 导出
   * @param e
   * @param ids 选中项
   * @param columnList 列配置
   */
  (e: 'deriveChange', ids: number[], columnList: SpColumnsType[]): void
  /**
   * 打印
   * @param e
   * @param ids 选中项
   * @param columnList 列配置
   */
  (e: 'printChange', ids: number[], columnList: SpColumnsType[]): void
  /**
   * 新增
   * @param e
   */
  (e: 'addChange'): void
}>()
// props
const props = defineProps<SpTableProps>()
// 复制一份表格字段
const newColumns = ref<SpColumnsType[]>(Object.assign(props.columnList))
// 批量删除按钮
const batchDeleteButton = ref(true)
// 分页当前页
const paginationCurrent = ref<number>(1)
// 主题色
const themeToken = getThemeTokenHook()
// 列配置下拉框是否默认显示
const columnConfigurationVisible = ref(false)
// 列配置下拉框数据
const columnCheckOptions = ref(Object.assign(props.columnList))
// 列配置下拉框数据
const columnConfiguration = reactive({
  indeterminate: false,
  checkAll: true,
  checkedList: Object.assign(props.columnList).map((item) => item.title)
})
// 表格大小
const size = ref([props.tableSize || 'middle'])
// 表格刷新动画
const tableRefreshClass = ref('')
// 拖拽
const drag = ref(true)

// 分页数据变化
const onPaginationChange = (page, pageSize) => {
  emit('paginationChange', page, pageSize)
}

// 批量删除
const onBatchDeleteChange = (ids: number[] | string[] | undefined) => {
  emit('batchDeleteChange', ids as number[])
}
// 导出
const onDeriveChange = (ids: number[] | string[] | undefined) => {
  emit('deriveChange', ids as number[], newColumns.value)
}
// 新增
const onAddChange = () => {
  emit('addChange')
}
// 打印
const onPrintChange = (ids: number[] | string[] | undefined) => {
  emit('printChange', ids as number[], newColumns.value)
}

// 列配置下拉框全选
const onCheckAllChange = (e: any) => {
  if (e.target.checked) {
    columnConfiguration.checkedList = Object.assign(props.columnList).map((item) => item.title)
  } else {
    columnConfiguration.checkedList = []
  }
}
// 列配置下拉框重置
function columnConfigurationReset() {
  columnConfiguration.checkedList = Object.assign(props.columnList).map((item) => item.title)
  columnConfiguration.checkAll = true
  columnConfiguration.indeterminate = false
  columnCheckOptions.value = Object.assign(props.columnList)
}
// 更新列配置
function updateColumnConfiguration() {
  newColumns.value = Object.assign(props.columnList).filter((item) =>
    columnConfiguration.checkedList.includes(item.title)
  )
}

// 表格刷新动画
function tableRefresh(page, pageSize) {
  tableRefreshClass.value = 'table-reload-click'
  onPaginationChange(page, pageSize)
  setTimeout(() => {
    tableRefreshClass.value = ''
  }, 500)
}

// 监听列配置变化
watch(
  () => columnConfiguration.checkedList,
  (val) => {
    columnConfiguration.indeterminate = !!val.length && val.length < columnCheckOptions.value.length
    columnConfiguration.checkAll = val.length === columnCheckOptions.value.length
    updateColumnConfiguration()
  }
)
// 监听列配置数据变化（拖拽）
watch(
  () => columnCheckOptions.value,
  (val) => {
    newColumns.value = val.filter((item) => columnConfiguration.checkedList.includes(item.title))
  }
)

// 监听选中项变化
watch(
  () => props.rowSelection?.selectedRowKeys,
  () => {
    batchDeleteButton.value = !props.rowSelection.selectedRowKeys?.length > 0
  }
)
</script>

<template>
  <div class="sp-table">
    <div v-if="deriveButton || deleteButton || addButton" class="sp-table-header">
      <div class="left">
        <a-button
          v-auth="[deleteButtonPerms]"
          v-if="deleteButton && rowSelection"
          :disabled="batchDeleteButton"
          danger
          :size="size[0]"
          type="primary"
          @click="onBatchDeleteChange(rowSelection?.selectedRowKeys)"
          >{{ transformI18n('btn.batchDelete') }}</a-button
        >

        <a-button
          v-auth="[deriveButtonPerms]"
          v-if="deriveButton"
          type="primary"
          :size="size[0]"
          @click="onDeriveChange(rowSelection?.selectedRowKeys)"
          >{{ transformI18n('btn.derivedExcel') }}</a-button
        >
        <a-button
          v-auth="[printButtonPerms]"
          v-if="printButton"
          type="default"
          :size="size[0]"
          @click="onPrintChange(rowSelection?.selectedRowKeys)"
          >{{ transformI18n('btn.print') }}</a-button
        >
      </div>

      <div class="right">
        <div class="right-btn">
          <a-button
            v-auth="[addButtonPerms]"
            :size="size[0]"
            v-if="addButton"
            type="primary"
            @click="onAddChange"
            >{{ transformI18n('btn.add') }}</a-button
          >
          <slot name="header-btn"></slot>
        </div>

        <div class="right-handle">
          <a-tooltip placement="bottom">
            <template #title>
              <span>{{ transformI18n('table.reload') }}</span>
            </template>
            <Icon
              :class="tableRefreshClass"
              class="table-reload table-header-hover"
              type="icon-reload"
              @click="tableRefresh(paging?.pageNum, paging?.pageSize)"
            />
          </a-tooltip>
          <a-divider type="vertical" />

          <a-dropdown placement="bottomRight">
            <a-tooltip placement="top">
              <template #title>
                <span>{{ transformI18n('table.density') }}</span>
              </template>
              <Icon class="table-header-hover" type="icon-colum-height" />
            </a-tooltip>
            <template #overlay>
              <a-menu v-model:selectedKeys="size" @click="(item) => (size[0] = item.key)">
                <a-menu-item key="large">{{ transformI18n('table.large') }} </a-menu-item>
                <a-menu-item key="middle">{{ transformI18n('table.middle') }} </a-menu-item>
                <a-menu-item key="small">{{ transformI18n('table.small') }} </a-menu-item>
              </a-menu>
            </template>
          </a-dropdown>

          <a-divider type="vertical" />

          <a-dropdown
            v-model:open="columnConfigurationVisible"
            :trigger="['click']"
            placement="bottomRight"
          >
            <a-tooltip placement="bottom">
              <template #title>
                <span>{{ transformI18n('table.columnConfiguration') }}</span>
              </template>
              <Icon class="table-header-hover" type="icon-setting" />
            </a-tooltip>
            <template #overlay>
              <div
                :style="{
                  background: themeToken.colorBgBase,
                  borderRadius: themeToken.borderRadius + 'px',
                  boxShadow: themeToken.boxShadowSecondary
                }"
                class="column-configuration"
              >
                <div
                  :style="{
                    borderBottom: '1px solid ' + themeToken.colorBorderSecondary
                  }"
                  class="column-configuration-header"
                >
                  <div class="left">
                    <a-checkbox
                      v-model:checked="columnConfiguration.checkAll"
                      :indeterminate="columnConfiguration.indeterminate"
                      @change="onCheckAllChange"
                    />
                    <span class="left-text">{{ transformI18n('table.columnShows') }}</span>
                  </div>
                  <div class="reset">
                    <a-button size="small" type="link" @click="columnConfigurationReset">{{
                      transformI18n('table.reset')
                    }}</a-button>
                  </div>
                </div>
                <div class="column-configuration-body">
                  <a-checkbox-group v-model:value="columnConfiguration.checkedList">
                    <Draggable
                      v-model="columnCheckOptions"
                      group="people"
                      item-key="id"
                      @end="drag = false"
                      @start="drag = true"
                    >
                      <template #item="{ element }">
                        <div class="column-configuration-item">
                          <Icon class="column-configuration-item-icon" type="icon-holder" />
                          <a-checkbox :value="element.title">{{ element.title }}</a-checkbox>
                        </div>
                      </template>
                    </Draggable>
                  </a-checkbox-group>
                </div>
              </div>
            </template>
          </a-dropdown>
        </div>
      </div>
    </div>
    <a-table
      :columns="newColumns"
      :data-source="data"
      :loading="loading ? loading : false"
      :pagination="false"
      :row-selection="rowSelection"
      :size="size[0]"
      v-bind="props"
      style="scrollbar-color: auto"
    >
      <template #bodyCell="{ text, record, index, column }">
        <template v-if="column.dataIndex === 'operation'">
          <div class="sp-table-operation">
            <slot name="operation" v-bind="{ text, record, index }"></slot>
          </div>
        </template>

        <!-- 自定义列渲染 -->
        <template v-else-if="column.cellRenderer">
          <!-- 渲染customRender -->
          <component :is="column.cellRenderer(record)"></component>
        </template>

        <template v-else-if="column.type == 'slot'">
          <slot :name="column.dataIndex" v-bind="{ text, record, index, size: size[0] }"></slot>
        </template>
      </template>
      <!-- 插槽透传 -->
      <template v-for="(value, name) in $slots" v-slot:[name]="slotProps">
        <slot :name="name" v-bind="slotProps"></slot>
      </template>
    </a-table>
    <div class="pagination">
      <a-pagination
        v-if="paging"
        v-model:current="paginationCurrent"
        :page-size="paging?.pageSize"
        :pageSizeOptions="['5', '10', '50', '100']"
        :total="paging?.total"
        show-quick-jumper
        :size="size[0]"
        @change="onPaginationChange"
      />
    </div>
  </div>
</template>

<style scoped>
.pagination {
  display: flex;
  margin-top: 20px;
  justify-content: flex-end;
}
.sp-table {
  .sp-table-header {
    display: flex;
    justify-content: space-between;
    margin-bottom: 15px;
    .ant-btn {
      margin-right: 15px;
    }
    .ant-btn:last-child {
      margin-right: 0;
    }
    .right {
      display: flex;
      align-items: center;
      .right-handle {
        cursor: pointer;
        margin-left: 20px;
        font-size: 16px;
        .table-reload-click {
          animation: table-reload-an 0.5s ease-in-out;
        }
        .table-header-hover {
          &:hover {
            color: v-bind(themeToken.colorPrimary);
          }
        }
      }
    }
  }
}

@keyframes table-reload-an {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

.column-configuration {
  width: 198px;
  padding: 10px 15px;
  margin-top: 15px;
  .column-configuration-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding-bottom: 8px;
    .left {
      .left-text {
        margin-left: 10px;
        font-size: 14px;
      }
    }
  }
  .column-configuration-item {
    width: 100%;
    height: 32px;
    display: flex;
    align-items: center;
    .column-configuration-item-icon {
      margin-right: 8px;
      font-size: 18px;
    }
  }
}
</style>
